#include "threadserialport.h"
#include "crc.h"

#include <QDebug>

ThreadSerialPort::ThreadSerialPort(QObject *parent)
    : QObject{parent}
{
    this->mThread = new QThread();
    this->mSerialPort = new QSerialPort();

    connect(this->mSerialPort, &QSerialPort::errorOccurred, this, [=](QSerialPort::SerialPortError error){
        emit signalSerialPortErrorOccurred(error);
    });

    connect(this->mSerialPort, &QSerialPort::readyRead, this, &ThreadSerialPort::slotHandlerReadyRead);

    this->mSerialPort->moveToThread(this->mThread);
    this->moveToThread(this->mThread);
    this->mThread->start();
}

ThreadSerialPort::~ThreadSerialPort()
{
    if (mThread->isRunning())
    {
        mThread->quit();
        mThread->wait();
        mThread->deleteLater();
        mThread = nullptr;
    }

    if (mSerialPort)
    {
        if (mSerialPort->isOpen())
        {
            mSerialPort->close();
        }

        delete mSerialPort;
        mSerialPort = nullptr;
    }
}

QString ThreadSerialPort::ByteArrayToHexSpaced(const QByteArray &data)
{
    QByteArray tmpArray = data.toHex().toUpper();
    QString hexSpaced;
    int size = tmpArray.size();
    for (int i = 0; i < size; ++i) {
        hexSpaced += tmpArray.at(i);
        if (i % 2 == 1 && i + 1 < size) {
            hexSpaced += " ";
        }
    }
    return hexSpaced;
}

void ThreadSerialPort::slotHandlerReadyRead()
{
    disconnect(this->mSerialPort, &QSerialPort::readyRead, this, &ThreadSerialPort::slotHandlerReadyRead);

    while (this->mSerialPort->waitForReadyRead(100))
    {
        recvData += this->mSerialPort->readAll();
    }

    if (0 != recvData.size())
    {
        emit signalReceivedData(recvData.data());
        recvData.clear();
    }

    connect(this->mSerialPort, &QSerialPort::readyRead, this, &ThreadSerialPort::slotHandlerReadyRead);
}


void ThreadSerialPort::slotOpenSerialPort(SerialPortSettings * settings)
{
    if (this->mSerialPort)
    {
        if (this->mSerialPort)
        {
            this->mSerialPort->close();
        }

        this->mSerialPort->setPortName(settings->portName);
        this->mSerialPort->setBaudRate(settings->baudrate);
        this->mSerialPort->setDataBits(settings->dataBits);
        this->mSerialPort->setParity(settings->parity);
        this->mSerialPort->setStopBits(settings->stopBits);
        this->mSerialPort->setFlowControl(settings->flowControl);

        emit signalOpenSerialPort(this->mSerialPort->open(QIODevice::ReadWrite), settings->portName);
    }
    else
    {
        emit signalOpenSerialPort(false, settings->portName);
    }
}

void ThreadSerialPort::slotCloseSerialPort()
{
    if (this->mSerialPort)
    {
        if (this->mSerialPort)
        {
            this->mSerialPort->close();
        }

        emit signalCloseSerialPort(!this->mSerialPort->isOpen());
    }
}

void ThreadSerialPort::slotTransmitData(QByteArray dataArray)
{
    QString errorStr = "";
    if (this->mSerialPort->isOpen())
    {
        this->mSerialPort->write(dataArray, dataArray.size());
        this->mSerialPort->flush();

        // qDebug() << "send:" << dataArray.toHex();
        qDebug() << "send:" << ByteArrayToHexSpaced(dataArray);
        emit signalTransmitData(ByteArrayToHexSpaced(dataArray));

        QByteArray recvData;
        quint16 regAddress = ((quint8)dataArray.at(2) << 8) | (quint8)dataArray.at(3);
        quint8 tranmitFunctionCode = (quint8)dataArray.at(1);


        while (this->mSerialPort->waitForReadyRead(100))
        {
            recvData += this->mSerialPort->readAll();
        }

        // qDebug() << "recv:" << ByteArrayToHexSpaced(recvData);
        emit signalReceivedData(ByteArrayToHexSpaced(recvData));

        if (!recvData.isEmpty())
        {
            /* 截取帧中的校验码 */
            quint8 frameCRC16 = *((quint16*)recvData.mid(recvData.size() - 2, 1).data());
            /* 通过帧中的数据重新计算校验码 */
            QByteArray tmpArray = recvData.mid(4, recvData.size() - (2 + 4));
            quint8 crc16 =  CRC::Calculate_CS(tmpArray, recvData.size() - (2 + 4));
            if (frameCRC16 == crc16)
            {
                emit signalReceivedAnswerFrame(recvData);
                // /* 校验通过 */
                // quint8 cmdCode = (quint8)recvData[1];
                // quint16 regValue = 0x00;

                // if ((0x03 == cmdCode) | (0x06 == cmdCode))
                // {
                //     switch (cmdCode){
                //     case 0x03: regValue = ((quint8)recvData.at(3) << 8) | (quint8)recvData.at(4);   break;
                //     default:                                                break;
                //     }

                //     if (regAddress < 1280)
                //     {
                //         /* 只读寄存器 */
                //         emit signalReceiveReadOnlyRegMsg(regAddress, regValue);
                //     }
                //     else
                //     {
                //         if (0x03 == cmdCode)
                //         {
                //             /* 可读写寄存器 */
                //             emit signalReceiveReadWriteRegMsg(regAddress, regValue);
                //         }
                //     }
                // }
                // else
                // {
                //     /* 功能码错误 */

                //     if (cmdCode == tranmitFunctionCode + 0x80)
                //     {
                //         quint8 errorCode = (quint8)recvData.at(2);
                //         switch (errorCode)
                //         {
                //         case 0x01: errorStr = "function code not support";  break;
                //         case 0x02: errorStr = "start address error";        break;
                //         case 0x03: errorStr = "request data length error";  break;
                //         case 0x04: errorStr = "date read/wirte failed";     break;
                //         default : break;
                //         }

                //     }
                //     else
                //     {
                //         errorStr = "function code error";
                //     }
                // }
            }
            else
            {
                /* 校验不通过 */
                errorStr = "crc wrong";
            }
        }
        else
        {
            errorStr = "time out";
        }
    }
    else
    {
        errorStr = "serial port not open";
    }

    emit signalTransmitErrorCode(errorStr);
}
